package uk.org.landeg.euler.problems;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import uk.org.landeg.euler.NumberFilter;
import uk.org.landeg.euler.PrimeGen;
import uk.org.landeg.euler.problems.framework.AbstractProblem;
import uk.org.landeg.euler.problems.framework.ProblemLauncher;
import uk.org.landeg.euler.problems.lib.NumbersLib;
import uk.org.landeg.euler.problems.lib.PrimeLib;

public class Problem051 extends AbstractProblem {
	public static void main(String[] args) {
		ProblemLauncher launcher = new ProblemLauncher(new Problem051());
		launcher.solve();
	}

	@Override
	public String getDescription() {
		// TODO Auto-generated method stub
		return "Find the smallest prime which, by replacing part of the number (not necessarily adjacent digits) with the same digit, is part of an eight prime value family.";
	}

	@Override
	public Integer getProblemNumber() {
		// TODO Auto-generated method stub
		return 51;
	}

	@Override
	public Object solve() {
		System.out.println("Creating primes");
//		Set<Integer> primes = PrimeLib.seqPrimes(9999);
		Set<Integer> primes = PrimeLib.seqPrimes(999999);
		Set<Integer> candidates = filterPrimeRange(primes);
		candidates = filterPrimeDigits(candidates);
		super.notes.add("Total primes disovered : " + primes.size());
		super.notes.add("Total candidates disovered : " + candidates.size());
		System.out.println(primes.size() + " candidate primes");
		return candidates.size();
//		Set<Integer> testSet = new HashSet<Integer> ();
//		testSet.add(12345);
//		testSet.add(123);
//		testSet.add(100001);
//		testSet.add(100023);
//		testSet.add(123456);
//		testSet.add(122234);
//		testSet.add(100203);
//		testSet = getDigitFreqFilter().doFilter(testSet);
//		System.out.println(testSet);
//		return 0;
	}

	protected Set<Integer> filterPrimeRange (Set<Integer> primes) {
		Set<Integer> filtered = new TreeSet<Integer>();
		int mod;
		for (int x : primes) {
			if (x <= 999999 && x >= 10000) {
				filtered.add(x);
			}
		}
		return filtered;
	}
	
	protected Set<Integer> filterPrimeDigits (Set<Integer> primes) {
		return getDigitFreqFilter().doFilter(primes);
	}
	
	private NumberFilter<Set<Integer>, Set<Integer>> digitFreqFilter = 
			new NumberFilter<Set<Integer>, Set<Integer>>() {
		int digitCount[];
		@Override
		public Set<Integer> doFilter(Set<Integer> param) {
			Set<Integer> filtered = new TreeSet<Integer>();
			List<Integer> match = new ArrayList<Integer>();
			Integer testValue;
			boolean foundTriplet;
			int d, lastDigit, len;
			for (int x : param) {
				lastDigit = x % 10;
				foundTriplet = false;
				len = NumbersLib.numericLength(x);
				digitCount = NumbersLib.digitCount(x);
				for (int id = 0 ; id < 3 ; id++) {
					d = digitCount[id];
					if (d == 3) {
						if (lastDigit != id) {
							foundTriplet = true;
							match = new ArrayList<Integer>();
							for (int replace = 0 ; replace <= 9 ; replace++) {
								testValue = NumbersLib.replaceDigits(x, id, replace);
								if (PrimeGen.isPrime(testValue)) {
									if (NumbersLib.numericLength(testValue) == len) {
										match.add(testValue);
									}
								}
							}
							if (match.size() == 8) {
								System.out.println(match.toString());
								break;
							}
							break;
						}
					}
				}
				if (foundTriplet) {
					filtered.add(x);
				}
			}
			return filtered;
		}
	};
	
	protected NumberFilter<Set<Integer>,Set<Integer>> getDigitFreqFilter () {
		return digitFreqFilter;
	}
}
